home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_lrm
/
chap13.doc
< prev
next >
Wrap
Text File
|
1996-01-30
|
48KB
|
1,139 lines
13. Representation Clauses and Implementation-Dependent Features
This chapter describes representation clauses, certain
implementation-dependent features, and other features that are used in
system programming.
13.1 Representation Clauses
Representation clauses specify how the types of the language are to be
mapped onto the underlying machine. They can be provided to give more
efficient representation or to interface with features that are outside the
domain of the language (for example, peripheral hardware).
representation_clause ::=
type_representation_clause | address_clause
type_representation_clause ::= length_clause
| enumeration_representation_clause | record_representation_clause
A type representation clause applies either to a type or to a first named
subtype (that is, to a subtype declared by a type declaration, the base
type being therefore anonymous). Such a representation clause applies to
all objects that have this type or this first named subtype. At most one
enumeration or record representation clause is allowed for a given type:
an enumeration representation clause is only allowed for an enumeration
type; a record representation clause, only for a record type. (On the
other hand, more than one length clause can be provided for a given type;
moreover, both a length clause and an enumeration or record representation
clause can be provided.) A length clause is the only form of
representation clause allowed for a type derived from a parent type that
has (user-defined) derivable subprograms.
An address clause applies either to an object; to a subprogram, package,
or task unit; or to an entry. At most one address clause is allowed for
any of these entities.
A representation clause and the declaration of the entity to which the
clause applies must both occur immediately within the same declarative
part, package specification, or task specification; the declaration must
occur before the clause. In the absence of a representation clause for a
given declaration, a default representation of this declaration is
determined by the implementation. Such a default determination occurs no
later than the end of the immediately enclosing declarative part, package
specification, or task specification. For a declaration given in a
declarative part, this default determination occurs before any enclosed
body.
In the case of a type, certain occurrences of its name imply that the
representation of the type must already have been determined. Consequently
these occurrences force the default determination of any aspect of the
representation not already determined by a prior type representation
clause. This default determination is also forced by similar occurrences
of the name of a subtype of the type, or of the name of any type or subtype
that has subcomponents of the type. A forcing occurrence is any occurrence
other than in a type or subtype declaration, a subprogram specification, an
entry declaration, a deferred constant declaration, a pragma, or a
representation clause for the type itself. In any case, an occurrence
within an expression is always forcing.
A representation clause for a given entity must not appear after an
occurrence of the name of the entity if this occurrence forces a default
determination of representation for the entity.
Similar restrictions exist for address clauses. For an object, any
occurrence of its name (after the object declaration) is a forcing
occurrence. For a subprogram, package, task unit, or entry, any occurrence
of a representation attribute of such an entity is a forcing occurrence.
The effect of the elaboration of a representation clause is to define the
corresponding aspects of the representation.
The interpretation of some of the expressions that appear in representation
clauses is implementation-dependent, for example, expressions specifying
addresses. An implementation may limit its acceptance of representation
clauses to those that can be handled simply by the underlying hardware. If
a representation clause is accepted by an implementation, the compiler must
guarantee that the net effect of the program is not changed by the presence
of the clause, except for address clauses and for parts of the program that
interrogate representation attributes. If a program contains a
representation clause that is not accepted, the program is illegal. For
each implementation, the allowed representation clauses, and the
conventions used for implementation-dependent expressions, must be
documented in Appendix F of the reference manual.
Whereas a representation clause is used to impose certain characteristics
of the mapping of an entity onto the underlying machine, pragmas can be
used to provide an implementation with criteria for its selection of such a
mapping. The pragma PACK specifies that storage minimization should be the
main criterion when selecting the representation of a record or array type.
Its form is as follows:
pragma PACK(type_simple_name);
Packing means that gaps between the storage areas allocated to consecutive
components should be minimized. It need not, however, affect the mapping
of each component onto storage. This mapping can itself be influenced by a
pragma (or controlled by a representation clause) for the component or
component type. The position of a PACK pragma, and the restrictions on the
named type, are governed by the same rules as for a representation clause;
in particular, the pragma must appear before any use of a representation
attribute of the packed entity.
The pragma PACK is the only language-defined representation pragma.
Additional representation pragmas may be provided by an implementation;
these must be documented in Appendix F. (In contrast to representation
clauses, a pragma that is not accepted by the implementation is ignored.)
Note:
No representation clause is allowed for a generic formal type.
References: address clause 13.5, allow 1.6, body 3.9, component 3.3,
declaration 3.1, declarative part 3.9, default expression 3.2.1, deferred
constant declaration 7.4, derivable subprogram 3.4, derived type 3.4,
entity 3.1, entry 9.5, enumeration representation clause 13.3, expression
4.4, generic formal type 12.1.2, illegal 1.6, length clause 13.2, must 1.6,
name 4.1, object 3.2, occur immediately within 8.1, package 7, package
specification 7.1, parent type 3.4, pragma 2.8, record representation
clause 13.4, representation attribute 13.7.2 13.7.3, subcomponent 3.3,
subprogram 6, subtype 3.3, subtype declaration 3.3.2, task specification
9.1, task unit 9, type 3.3, type declaration 3.3.1
13.2 Length Clauses
A length clause specifies an amount of storage associated with a type.
length_clause ::= for attribute use simple_expression;
The expression must be of some numeric type and is evaluated during the
elaboration of the length clause (unless it is a static expression). The
prefix of the attribute must denote either a type or a first named subtype.
The prefix is called T in what follows. The only allowed attribute
designators in a length clause are SIZE, STORAGE_SIZE, and SMALL. The
effect of the length clause depends on the attribute designator:
(a) Size specification: T'SIZE
The expression must be a static expression of some integer type. The
value of the expression specifies an upper bound for the number of
bits to be allocated to objects of the type or first named subtype T.
The size specification must allow for enough storage space to
accommodate every allowable value of these objects. A size
specification for a composite type may affect the size of the gaps
between the storage areas allocated to consecutive components. On the
other hand, it need not affect the size of the storage area allocated
to each component.
The size specification is only allowed if the constraints on T and on
its subcomponents (if any) are static. In the case of an
unconstrained array type, the index subtypes must also be static.
(b) Specification of collection size: T'STORAGE_SIZE
The prefix T must denote an access type. The expression must be of
some integer type (but need not be static); its value specifies the
number of storage units to be reserved for the collection, that is,
the storage space needed to contain all objects designated by values
of the access type and by values of other types derived from the
access type, directly or indirectly. This form of length clause is
not allowed for a type derived from an access type.
(c) Specification of storage for a task activation: T'STORAGE_SIZE
The prefix T must denote a task type. The expression must be of some
integer type (but need not be static); its value specifies the number
of storage units to be reserved for an activation (not the code) of a
task of the type.
(d) Specification of small for a fixed point type: T'SMALL
The prefix T must denote the first named subtype of a fixed point
type. The expression must be a static expression of some real type;
its value must not be greater than the delta of the first named
subtype. The effect of the length clause is to use this value of
small for the representation of values of the fixed point base type.
(The length clause thereby also affects the amount of storage for
objects that have this type.)
Notes:
A size specification is allowed for an access, task, or fixed point type,
whether or not another form of length clause is also given for the type.
What is considered to be part of the storage reserved for a collection or
for an activation of a task is implementation-dependent. The control
afforded by length clauses is therefore relative to the implementation
conventions. For example, the language does not define whether the storage
reserved for an activation of a task includes any storage needed for the
collection associated with an access type declared within the task body.
Neither does it define the method of allocation for objects denoted by
values of an access type. For example, the space allocated could be on a
stack; alternatively, a general dynamic allocation scheme or fixed
storage could be used.
The objects allocated in a collection need not have the same size if the
designated type is an unconstrained array type or an unconstrained type
with discriminants. Note also that the allocator itself may require some
space for internal tables and links. Hence a length clause for the
collection of an access type does not always give precise control over the
maximum number of allocated objects.
Examples:
-- assumed declarations:
type MEDIUM is range 0 .. 65000;
type SHORT is delta 0.01 range -100.0 .. 100.0;
type DEGREE is delta 0.1 range -360.0 .. 360.0;
BYTE : constant := 8;
PAGE : constant := 2000;
-- length clauses:
for COLOR'SIZE use 1*BYTE; -- see 3.5.1
for MEDIUM'SIZE use 2*BYTE;
for SHORT'SIZE use 15;
for CAR_NAME'STORAGE_SIZE use -- approximately 2000 cars
2000*((CAR'SIZE/SYSTEM.STORAGE_UNIT) + 1);
for KEYBOARD_DRIVER'STORAGE_SIZE use 1*PAGE;
for DEGREE'SMALL use 360.0/2**(SYSTEM.STORAGE_UNIT - 1);
Notes on the examples:
In the length clause for SHORT, fifteen bits is the minimum necessary,
since the type definition requires SHORT'SMALL = 2.0**(-7) and
SHORT'MANTISSA = 14. The length clause for DEGREE forces the model numbers
to exactly span the range of the type.
References: access type 3.8, allocator 4.8, allow 1.6, array type 3.6,
attribute 4.1.4, collection 3.8, composite type 3.3, constraint 3.3, delta
of a fixed point type 3.5.9, derived type 3.4, designate 3.8, elaboration
3.9, entity 3.1, evaluation 4.5, expression 4.4, first named subtype 13.1,
fixed point type 3.5.9, index subtype 3.6, integer type 3.5.4, must 1.6,
numeric type 3.5, object 3.2, real type 3.5.6, record type 3.7, small of a
fixed point type 3.5.10, static constraint 4.9, static expression 4.9,
static subtype 4.9, storage unit 13.7, subcomponent 3.3, system package
13.7, task 9, task activation 9.3, task specification 9.1, task type 9.2,
type 3.3, unconstrained array type 3.6
13.3 Enumeration Representation Clauses
An enumeration representation clause specifies the internal codes for the
literals of the enumeration type that is named in the clause.
enumeration_representation_clause ::= for type_simple_name use aggregate;
The aggregate used to specify this mapping is written as a one-dimensional
aggregate, for which the index subtype is the enumeration type and the
component type is universal_integer.
All literals of the enumeration type must be provided with distinct integer
codes, and all choices and component values given in the aggregate must be
static. The integer codes specified for the enumeration type must satisfy
the predefined ordering relation of the type.
Example:
type MIX_CODE is (ADD, SUB, MUL, LDA, STA, STZ);
for MIX_CODE use
(ADD => 1, SUB => 2, MUL => 3, LDA => 8, STA => 24, STZ => 33);
Notes:
The attributes SUCC, PRED, and POS are defined even for enumeration types
with a noncontiguous representation; their definition corresponds to the
(logical) type declaration and is not affected by the enumeration
representation clause. In the example, because of the need to avoid the
omitted values, these functions are likely to be less efficiently
implemented than they could be in the absence of a representation clause.
Similar considerations apply when such types are used for indexing.
References: aggregate 4.3, array aggregate 4.3.2, array type 3.6,
attribute of an enumeration type 3.5.5, choice 3.7.3, component 3.3,
enumeration literal 3.5.1, enumeration type 3.5.1, function 6.5, index 3.6,
index subtype 3.6, literal 4.2, ordering relation of an enumeration type
3.5.1, representation clause 13.1, simple name 4.1, static expression 4.9,
type 3.3, type declaration 3.3.1, universal_integer type 3.5.4
13.4 Record Representation Clauses
A record representation clause specifies the storage representation of
records, that is, the order, position, and size of record components
(including discriminants, if any).
record_representation_clause ::=
for type_simple_name use
record [alignment_clause]
{component_clause}
end record;
alignment_clause ::= at mod static_simple_expression;
component_clause ::=
component_name at static_simple_expression range static_range;
The simple expression given after the reserved words at mod in an alignment
clause, or after the reserved word at in a component clause, must be a
static expression of some integer type. If the bounds of the range of a
component clause are defined by simple expressions, then each bound of the
range must be defined by a static expression of some integer type, but the
two bounds need not have the same integer type.
An alignment clause forces each record of the given type to be allocated at
a starting address that is a multiple of the value of the given expression
(that is, the address modulo the expression must be zero). An
implementation may place restrictions on the allowable alignments.
A component clause specifies the storage place of a component, relative to
the start of the record. The integer defined by the static expression of a
component clause is a relative address expressed in storage units. The
range defines the bit positions of the storage place, relative to the
storage unit. The first storage unit of a record is numbered zero. The
first bit of a storage unit is numbered zero. The ordering of bits in a
storage unit is machine-dependent and may extend to adjacent storage units.
(For a specific machine, the size in bits of a storage unit is given by the
configuration-dependent named number SYSTEM.STORAGE_UNIT.) Whether a
component is allowed to overlap a storage boundary, and if so, how, is
implementation-defined.
At most one component clause is allowed for each component of the record
type, including for each discriminant (component clauses may be given for
some, all, or none of the components). If no component clause is given for
a component, then the choice of the storage place for the component is left
to the compiler. If component clauses are given for all components, the
record representation clause completely specifies the representation of the
record type and must be obeyed exactly by the compiler.
Storage places within a record variant must not overlap, but overlap of the
storage for distinct variants is allowed. Each component clause must allow
for enough storage space to accommodate every allowable value of the
component. A component clause is only allowed for a component if any
constraint on this component or on any of its subcomponents is static.
An implementation may generate names that denote implementation-dependent
components (for example, one containing the offset of another component).
Such implementation-dependent names can be used in record representation
clauses (these names need not be simple names; for example, they could be
implementation-dependent attributes).
Example:
WORD : constant := 4; -- storage unit is byte, 4 bytes per word
type STATE is (A, M, W, P);
type MODE is (FIX, DEC, EXP, SIGNIF);
type BYTE_MASK is array (0 .. 7) of BOOLEAN;
type STATE_MASK is array (STATE) of BOOLEAN;
type MODE_MASK is array (MODE) of BOOLEAN;
type PROGRAM_STATUS_WORD is
record
SYSTEM_MASK : BYTE_MASK;
PROTECTION_KEY : INTEGER range 0 .. 3;
MACHINE_STATE : STATE_MASK;
INTERRUPT_CAUSE : INTERRUPTION_CODE;
ILC : INTEGER range 0 .. 3;
CC : INTEGER range 0 .. 3;
PROGRAM_MASK : MODE_MASK;
INST_ADDRESS : ADDRESS;
end record;
for PROGRAM_STATUS_WORD use
record at mod 8;
SYSTEM_MASK at 0*WORD range 0 .. 7;
PROTECTION_KEY at 0*WORD range 10 .. 11; -- bits 8, 9 unused
MACHINE_STATE at 0*WORD range 12 .. 15;
INTERRUPT_CAUSE at 0*WORD range 16 .. 31;
ILC at 1*WORD range 0 .. 1; -- second word
CC at 1*WORD range 2 .. 3;
PROGRAM_MASK at 1*WORD range 4 .. 7;
INST_ADDRESS at 1*WORD range 8 .. 31;
end record;
for PROGRAM_STATUS_WORD'SIZE use 8*SYSTEM.STORAGE_UNIT;
Note on the example:
The record representation clause defines the record layout. The length
clause guarantees that exactly eight storage units are used.
References: allow 1.6, attribute 4.1.4, constant 3.2.1, constraint 3.3,
discriminant 3.7.1, integer type 3.5.4, must 1.6, named number 3.2, range
3.5, record component 3.7, record type 3.7, simple expression 4.4, simple
name 4.1, static constraint 4.9, static expression 4.9, storage unit 13.7,
subcomponent 3.3, system package 13.7, variant 3.7.3
13.5 Address Clauses
An address clause specifies a required address in storage for an entity.
address_clause ::= for simple_name use at simple_expression;
The expression given after the reserved word at must be of the type ADDRESS
defined in the package SYSTEM (see 13.7); this package must be named by a
with clause that applies to the compilation unit in which the address
clause occurs. The conventions that define the interpretation of a value
of the type ADDRESS as an address, as an interrupt level, or whatever it
may be, are implementation-dependent. The allowed nature of the simple
name and the meaning of the corresponding address are as follows:
(a) Name of an object: the address is that required for the object
(variable or constant).
(b) Name of a subprogram, package, or task unit: the address is that
required for the machine code associated with the body of the program
unit.
(c) Name of a single entry: the address specifies a hardware interrupt to
which the single entry is to be linked.
If the simple name is that of a single task, the address clause is
understood to refer to the task unit and not to the task object. In all
cases, the address clause is only legal if exactly one declaration with
this identifier occurs earlier, immediately within the same declarative
part, package specification, or task specification. A name declared by a
renaming declaration is not allowed as the simple name.
Address clauses should not be used to achieve overlays of objects or
overlays of program units. Nor should a given interrupt be linked to more
than one entry. Any program using address clauses to achieve such effects
is erroneous.
Example:
for CONTROL use at 16#0020#; -- assuming that SYSTEM.ADDRESS is an integer type
Notes:
The above rules imply that if two subprograms overload each other and are
visible at a given point, an address clause for any of them is not legal at
this point. Similarly if a task specification declares entries that
overload each other, they cannot be interrupt entries. The syntax does not
allow an address clause for a library unit. An implementation may provide
pragmas for the specification of program overlays.
References: address predefined type 13.7, apply 10.1.1, compilation unit
10.1, constant 3.2.1, entity 3.1, entry 9.5, erroneous 1.6, expression 4.4,
library unit 10.1, name 4.1, object 3.2, package 7, pragma 2.8, program
unit 6, reserved word 2.9, simple expression 4.4, simple name 4.1,
subprogram 6, subprogram body 6.3, system package 13.7, task body 9.1, task
object 9.2, task unit 9, type 3.3, variable 3.2.1, with clause 10.1.1
13.5.1 Interrupts
An address clause given for an entry associates the entry with some device
that may cause an interrupt; such an entry is referred to in this section
as an interrupt entry. If control information is supplied upon an
interrupt, it is passed to an associated interrupt entry as one or more
parameters of mode in; only parameters of this mode are allowed.
An interrupt acts as an entry call issued by a hardware task whose priority
is higher than the priority of the main program, and also higher than the
priority of any user-defined task (that is, any task whose type is declared
by a task unit in the program). The entry call may be an ordinary entry
call, a timed entry call, or a conditional entry call, depending on the
kind of interrupt and on the implementation.
If a select statement contains both a terminate alternative and an accept
alternative for an interrupt entry, then an implementation may impose
further requirements for the selection of the terminate alternative in
addition to those given in section 9.4.
Example:
task INTERRUPT_HANDLER is
entry DONE;
for DONE use at 16#40#; -- assuming that SYSTEM.ADDRESS is an integer type
end INTERRUPT_HANDLER;
Notes:
Interrupt entry calls need only have the semantics described above; they
may be implemented by having the hardware directly execute the appropriate
accept statements.
Queued interrupts correspond to ordinary entry calls. Interrupts that are
lost if not immediately processed correspond to conditional entry calls.
It is a consequence of the priority rules that an accept statement executed
in response to an interrupt takes precedence over ordinary, user-defined
tasks, and can be executed without first invoking a scheduling action.
One of the possible effects of an address clause for an interrupt entry is
to specify the priority of the interrupt (directly or indirectly). Direct
calls to an interrupt entry are allowed.
References: accept alternative 9.7.1, accept statement 9.5, address
predefined type 13.7, allow 1.6, conditional entry call 9.7.2, entry 9.5,
entry call 9.5, mode 6.1, parameter of a subprogram 6.2, priority of a task
9.8, select alternative 9.7.1, select statement 9.7, system package 13.7,
task 9, terminate alternative 9.7.1, timed entry call 9.7.3
13.6 Change of Representation
At most one representation clause is allowed for a given type and a given
aspect of its representation. Hence, if an alternative representation is
needed, it is necessary to declare a second type, derived from the first,
and to specify a different representation for the second type.
Example:
-- PACKED_DESCRIPTOR and DESCRIPTOR are two different types
-- with identical characteristics, apart from their representation
type DESCRIPTOR is
record
-- components of a descriptor
end record;
type PACKED_DESCRIPTOR is new DESCRIPTOR;
for PACKED_DESCRIPTOR use
record
-- component clauses for some or for all components
end record;
Change of representation can now be accomplished by assignment with
explicit type conversions:
D : DESCRIPTOR;
P : PACKED_DESCRIPTOR;
P := PACKED_DESCRIPTOR(D); -- pack D
D := DESCRIPTOR(P); -- unpack P
References: assignment 5.2, derived type 3.4, type 3.3, type conversion
4.6, type declaration 3.1, representation clause 13.1
13.7 The Package System
For each implementation there is a predefined library package called SYSTEM
which includes the definitions of certain configuration-dependent
characteristics. The specification of the package SYSTEM is
implementation-dependent and must be given in Appendix F. The visible part
of this package must contain at least the following declarations.
package SYSTEM is
type ADDRESS is implementation_defined;
type NAME is implementation_defined_enumeration_type;
SYSTEM_NAME : constant NAME := implementation_defined;
STORAGE_UNIT : constant := implementation_defined;
MEMORY_SIZE : constant := implementation_defined;
-- System-Dependent Named Numbers:
MIN_INT : constant := implementation_defined;
MAX_INT : constant := implementation_defined;
MAX_DIGITS : constant := implementation_defined;
MAX_MANTISSA : constant := implementation_defined;
FINE_DELTA : constant := implementation_defined;
TICK : constant := implementation_defined;
-- Other System-Dependent Declarations
subtype PRIORITY is INTEGER range implementation_defined;
...
end SYSTEM;
The type ADDRESS is the type of the addresses provided in address clauses;
it is also the type of the result delivered by the attribute ADDRESS.
Values of the enumeration type NAME are the names of alternative machine
configurations handled by the implementation; one of these is the constant
SYSTEM_NAME. The named number STORAGE_UNIT is the number of bits per
storage unit; the named number MEMORY_SIZE is the number of available
storage units in the configuration; these named numbers are of the type
universal_integer.
An alternative form of the package SYSTEM, with given values for any of
SYSTEM_NAME, STORAGE_UNIT, and MEMORY_SIZE, can be obtained by means of the
corresponding pragmas. These pragmas are only allowed at the start of a
compilation, before the first compilation unit (if any) of the compilation.
pragma SYSTEM_NAME(enumeration_literal);
The effect of the above pragma is to use the enumeration literal with the
specified identifier for the definition of the constant SYSTEM_NAME. This
pragma is only allowed if the specified identifier corresponds to one of
the literals of the type NAME.
pragma STORAGE_UNIT(numeric_literal);
The effect of the above pragma is to use the value of the specified numeric
literal for the definition of the named number STORAGE_UNIT.
pragma MEMORY_SIZE(numeric_literal);
The effect of the above pragma is to use the value of the specified numeric
literal for the definition of the named number MEMORY_SIZE.
The compilation of any of these pragmas causes an implicit recompilation of
the package SYSTEM. Consequently any compilation unit that names SYSTEM in
its context clause becomes obsolete after this implicit recompilation. An
implementation may impose further limitations on the use of these pragmas.
For example, an implementation may allow them only at the start of the
first compilation, when creating a new program library.
Note:
It is a consequence of the visibility rules that a declaration given in the
package SYSTEM is not visible in a compilation unit unless this package is
mentioned by a with clause that applies (directly or indirectly) to the
compilation unit.
References: address clause 13.5, apply 10.1.1, attribute 4.1.4,
compilation unit 10.1, declaration 3.1, enumeration literal 3.5.1,
enumeration type 3.5.1, identifier 2.3, library unit 10.1, must 1.6, named
number 3.2, number declaration 3.2.2, numeric literal 2.4, package 7,
package specification 7.1, pragma 2.8, program library 10.1, type 3.3,
visibility 8.3, visible part 7.2, with clause 10.1.1
13.7.1 System-Dependent Named Numbers
Within the package SYSTEM, the following named numbers are declared. The
numbers FINE_DELTA and TICK are of the type universal_real; the others are
of the type universal_integer.
MIN_INT The smallest (most negative) value of all predefined integer
types.
MAX_INT The largest (most positive) value of all predefined integer
types.
MAX_DIGITS The largest value allowed for the number of significant
decimal digits in a floating point constraint.
MAX_MANTISSA The largest possible number of binary digits in the mantissa
of model numbers of a fixed point subtype.
FINE_DELTA The smallest delta allowed in a fixed point constraint that
has the range constraint -1.0 .. 1.0.
TICK The basic clock period, in seconds.
References: allow 1.6, delta of a fixed point constraint 3.5.9, fixed
point constraint 3.5.9, floating point constraint 3.5.7, integer type
3.5.4, model number 3.5.6, named number 3.2, package 7, range constraint
3.5, system package 13.7, type 3.3, universal_integer type 3.5.4,
universal_real type 3.5.6
13.7.2 Representation Attributes
The values of certain implementation-dependent characteristics can be
obtained by interrogating appropriate representation attributes. These
attributes are described below.
For any object, program unit, label, or entry X:
X'ADDRESS Yields the address of the first of the storage units
allocated to X. For a subprogram, package, task unit or
label, this value refers to the machine code associated
with the corresponding body or statement. For an entry for
which an address clause has been given, the value refers to
the corresponding hardware interrupt. The value of this
attribute is of the type ADDRESS defined in the package
SYSTEM.
For any type or subtype X, or for any object X:
X'SIZE Applied to an object, yields the number of bits allocated
to hold the object. Applied to a type or subtype, yields
the minimum number of bits that is needed by the
implementation to hold any possible object of this type or
subtype. The value of this attribute is of the type
universal_integer.
For the above two representation attributes, if the prefix is the name of a
function, the attribute is understood to be an attribute of the function
(not of the result of calling the function). Similarly, if the type of the
prefix is an access type, the attribute is understood to be an attribute of
the prefix (not of the designated object: attributes of the latter can be
written with a prefix ending with the reserved word all).
For any component C of a record object R:
R.C'POSITION Yields the offset, from the start of the first storage unit
occupied by the record, of the first of the storage units
occupied by C. This offset is measured in storage units.
The value of this attribute is of the type
universal_integer.
R.C'FIRST_BIT Yields the offset, from the start of the first of the
storage units occupied by C, of the first bit occupied by
C. This offset is measured in bits. The value of this
attribute is of the type universal_integer.
R.C'LAST_BIT Yields the offset, from the start of the first of the
storage units occupied by C, of the last bit occupied by C.
This offset is measured in bits. The value of this
attribute is of the type universal_integer.
For any access type or subtype T:
T'STORAGE_SIZE Yields the total number of storage units reserved for the
collection associated with the base type of T. The value
of this attribute is of the type universal_integer.
For any task type or task object T:
T'STORAGE_SIZE Yields the number of storage units reserved for each
activation of a task of the type T or for the activation of
the task object T. The value of this attribute is of the
type universal_integer.
Notes:
For a task object X, the attribute X'SIZE gives the number of bits used to
hold the object X, whereas X'STORAGE_SIZE gives the number of storage units
allocated for the activation of the task designated by X. For a formal
parameter X, if parameter passing is achieved by copy, then the attribute
X'ADDRESS yields the address of the local copy; if parameter passing is by
reference, then the address is that of the actual parameter.
References: access subtype 3.8, access type 3.8, activation 9.3, actual
parameter 6.2, address clause 13.5, address predefined type 13.7, attribute
4.1.4, base type 3.3, collection 3.8, component 3.3, entry 9.5, formal
parameter 6.1 6.2, label 5.1, object 3.2, package 7, package body 7.1,
parameter passing 6.2, program unit 6, record object 3.7, statement 5,
storage unit 13.7, subprogram 6, subprogram body 6.3, subtype 3.3, system
predefined package 13.7, task 9, task body 9.1, task object 9.2, task type
9.2, task unit 9, type 3.3, universal_integer type 3.5.4
13.7.3 Representation Attributes of Real Types
For every real type or subtype T, the following machine-dependent
attributes are defined, which are not related to the model numbers.
Programs using these attributes may thereby exploit properties that go
beyond the minimal properties associated with the numeric type (see section
4.5.7 for the rules defining the accuracy of operations with real
operands). Precautions must therefore be taken when using these
machine-dependent attributes if portability is to be ensured.
For both floating point and fixed point types:
T'MACHINE_ROUNDS Yields the value TRUE if every predefined arithmetic
operation on values of the base type of T either
returns an exact result or performs rounding;
yields the value FALSE otherwise. The value of this
attribute is of the predefined type BOOLEAN.
T'MACHINE_OVERFLOWS Yields the value TRUE if every predefined operation
on values of the base type of T either provides a
correct result, or raises the exception
NUMERIC_ERROR in overflow situations (see 4.5.7);
yields the value FALSE otherwise. The value of this
attribute is of the predefined type BOOLEAN.
For floating point types, the following attributes provide characteristics
of the underlying machine representation, in terms of the canonical form
defined in section 3.5.7:
T'MACHINE_RADIX Yields the value of the radix used by the machine
representation of the base type of T. The value of
this attribute is of the type universal_integer.
T'MACHINE_MANTISSA Yields the number of digits in the mantissa for the
machine representation of the base type of T (the
digits are extended digits in the range 0 to
T'MACHINE_RADIX -1). The value of this attribute is
of the type universal_integer.
T'MACHINE_EMAX Yields the largest value of exponent for the machine
representation of the base type of T. The value of
this attribute is of the type universal_integer.
T'MACHINE_EMIN Yields the smallest (most negative) value of
exponent for the machine representation of the base
type of T. The value of this attribute is of the
type universal_integer.
Note:
For many machines the largest machine representable number of type F is
almost
(F'MACHINE_RADIX)**(F'MACHINE_EMAX),
and the smallest positive representable number is
F'MACHINE_RADIX ** (F'MACHINE_EMIN - 1)
References: arithmetic operator 4.5, attribute 4.1.4, base type 3.3,
boolean predefined type 3.5.3, false boolean value 3.5.3, fixed point type
3.5.9, floating point type 3.5.7, model number 3.5.6, numeric type 3.5,
numeric_error exception 11.1, predefined operation 3.3.3, radix 3.5.7, real
type 3.5.6, subtype 3.3, true boolean value 3.5.3, type 3.3,
universal_integer type 3.5.4
13.8 Machine Code Insertions
A machine code insertion can be achieved by a call to a procedure whose
sequence of statements contains code statements.
code_statement ::= type_mark'record_aggregate;
A code statement is only allowed in the sequence of statements of a
procedure body. If a procedure body contains code statements, then within
this procedure body the only allowed form of statement is a code statement
(labeled or not), the only allowed declarative items are use clauses, and
no exception handler is allowed (comments and pragmas are allowed as
usual).
Each machine instruction appears as a record aggregate of a record type
that defines the corresponding instruction. The base type of the type mark
of a code statement must be declared within the predefined library package
called MACHINE_CODE; this package must be named by a with clause that
applies to the compilation unit in which the code statement occurs. An
implementation is not required to provide such a package.
An implementation is allowed to impose further restrictions on the record
aggregates allowed in code statements. For example, it may require that
expressions contained in such aggregates be static expressions.
An implementation may provide machine-dependent pragmas specifying register
conventions and calling conventions. Such pragmas must be documented in
Appendix F.
Example:
M : MASK;
procedure SET_MASK; pragma INLINE(SET_MASK);
procedure SET_MASK is
use MACHINE_CODE;
begin
SI_FORMAT'(CODE => SSM, B => M'BASE_REG, D => M'DISP);
-- M'BASE_REG and M'DISP are implementation-specific predefined attributes
end;
References: allow 1.6, apply 10.1.1, comment 2.7, compilation unit 10.1,
declarative item 3.9, exception handler 11.2, inline pragma 6.3.2, labeled
statement 5.1, library unit 10.1, package 7, pragma 2.8, procedure 6 6.1,
procedure body 6.3, record aggregate 4.3.1, record type 3.7, sequence of
statements 5.1, statement 5, static expression 4.9, use clause 8.4, with
clause 10.1.1
13.9 Interface to Other Languages
A subprogram written in another language can be called from an Ada program
provided that all communication is achieved via parameters and function
results. A pragma of the form
pragma INTERFACE (language_name, subprogram_name);
must be given for each such subprogram; a subprogram name is allowed to
stand for several overloaded subprograms. This pragma is allowed at the
place of a declarative item, and must apply in this case to a subprogram
declared by an earlier declarative item of the same declarative part or
package specification. The pragma is also allowed for a library unit; in
this case the pragma must appear after the subprogram declaration, and
before any subsequent compilation unit. The pragma specifies the other
language (and thereby the calling conventions) and informs the compiler
that an object module will be supplied for the corresponding subprogram. A
body is not allowed for such a subprogram (not even in the form of a body
stub) since the instructions of the subprogram are written in another
language.
This capability need not be provided by all implementations. An
implementation may place restrictions on the allowable forms and places of
parameters and calls.
Example:
package FORT_LIB is
function SQRT(X : FLOAT) return FLOAT;
function EXP (X : FLOAT) return FLOAT;
private
pragma INTERFACE(FORTRAN, SQRT);
pragma INTERFACE(FORTRAN, EXP);
end FORT_LIB;
Notes:
The conventions used by other language processors that call Ada programs
are not part of the Ada language definition. Such conventions must be
defined by these other language processors.
The pragma INTERFACE is not defined for generic subprograms.
References: allow 1.6, body stub 10.2, compilation unit 10.1, declaration
3.1, declarative item 3.9, declarative part 3.9, function result 6.5,
library unit 10.1, must 1.6, name 4.1, overloaded subprogram 6.6, package
specification 7.1, parameter of a subprogram 6.2, pragma 2.8, subprogram 6,
subprogram body 6.3, subprogram call 6.4, subprogram declaration 6.1
13.10 Unchecked Programming
The predefined generic library subprograms UNCHECKED_DEALLOCATION and
UNCHECKED_CONVERSION are used for unchecked storage deallocation and for
unchecked type conversions.
generic
type OBJECT is limited private;
type NAME is access OBJECT;
procedure UNCHECKED_DEALLOCATION(X : in out NAME);
generic
type SOURCE is limited private;
type TARGET is limited private;
function UNCHECKED_CONVERSION(S : SOURCE) return TARGET;
References: generic subprogram 12.1, library unit 10.1, type 3.3
13.10.1 Unchecked Storage Deallocation
Unchecked storage deallocation of an object designated by a value of an
access type is achieved by a call of a procedure that is obtained by
instantiation of the generic procedure UNCHECKED_DEALLOCATION. For
example:
procedure FREE is new UNCHECKED_DEALLOCATION(object_type_name, access_type_name);
Such a FREE procedure has the following effect:
(a) after executing FREE(X), the value of X is null;
(b) FREE(X), when X is already equal to null, has no effect;
(c) FREE(X), when X is not equal to null, is an indication that the object
designated by X is no longer required, and that the storage it
occupies is to be reclaimed.
If X and Y designate the same object, then accessing this object through Y
is erroneous if this access is performed (or attempted) after the call
FREE(X); the effect of each such access is not defined by the language.
Notes:
It is a consequence of the visibility rules that the generic procedure
UNCHECKED_DEALLOCATION is not visible in a compilation unit unless this
generic procedure is mentioned by a with clause that applies to the
compilation unit.
If X designates a task object, the call FREE(X) has no effect on the task
designated by the value of this task object. The same holds for any
subcomponent of the object designated by X, if this subcomponent is a task
object.
References: access type 3.8, apply 10.1.1, compilation unit 10.1,
designate 3.8 9.1, erroneous 1.6, generic instantiation 12.3, generic
procedure 12.1, generic unit 12, library unit 10.1, null access value 3.8,
object 3.2, procedure 6, procedure call 6.4, subcomponent 3.3, task 9, task
object 9.2, visibility 8.3, with clause 10.1.1
13.10.2 Unchecked Type Conversions
An unchecked type conversion can be achieved by a call of a function that
is obtained by instantiation of the generic function UNCHECKED_CONVERSION.
The effect of an unchecked conversion is to return the (uninterpreted)
parameter value as a value of the target type, that is, the bit pattern
defining the source value is returned unchanged as the bit pattern defining
a value of the target type. An implementation may place restrictions on
unchecked conversions, for example, restrictions depending on the
respective sizes of objects of the source and target type. Such
restrictions must be documented in appendix F.
Whenever unchecked conversions are used, it is the programmer's
responsibility to ensure that these conversions maintain the properties
that are guaranteed by the language for objects of the target type.
Programs that violate these properties by means of unchecked conversions
are erroneous.
Note:
It is a consequence of the visibility rules that the generic function
UNCHECKED_CONVERSION is not visible in a compilation unit unless this
generic function is mentioned by a with clause that applies to the
compilation unit.
References: apply 10.1.1, compilation unit 10.1, erroneous 1.6, generic
function 12.1, instantiation 12.3, parameter of a subprogram 6.2, type 3.3,
with clause 10.1.1